﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using BlobNet.Base.DataProviders;
using BlobNet.Base.Enums;
using BlobNet.Base.Storage;

namespace BlobNet.Base
{
    //TODO:quit comment [DebuggerStepThrough]
    [Serializable]
    public abstract class BlobDomain : BlobPart
    {
        #region Attributes

        private readonly bool _canKeepStatusInDb;
        private readonly IDataProvider _dataProvider;
        private bool _dbCreated;

        #endregion Attributes

        #region Constructors

        protected BlobDomain(Guid entityId) : this(entityId, true)
        {}

        //TODO: Simplify these constructors
        internal BlobDomain(Guid entityId, IStorageManagerFactory statusStorageFactory)
            : this(entityId, statusStorageFactory, true)
        {}

        internal BlobDomain(Guid entityId, bool canKeepStatusInDb)
            : this(entityId, new StorageFactory(), canKeepStatusInDb)
        {}

        internal BlobDomain(Guid entityId, IStorageManagerFactory statusStorageFactory, bool canKeepStatusInDb)
            : base(null, entityId, statusStorageFactory)
        {

            _dataProvider = DataProviderFactory.Provider;
            if (_dataProvider!=null && _dataProvider.ExistsBlobDomain(entityId))
            {
                _canKeepStatusInDb = true;
                ChangeStorage(StatusStorageType.Persistent);
            }
            else
            {
                _canKeepStatusInDb = canKeepStatusInDb && _dataProvider!=null;
                if (_canKeepStatusInDb)
                    KeepStatusInDataProvider();
            }
        }

        #endregion Constructors

        #region Not Public Properties

        protected internal virtual IDataProvider DataProvider
        {
            get { return _dataProvider; }
        }

        public override BlobDomain Domain
        {
            get { return this; }
        }

        private bool DbCreated
        {
            get { return _dbCreated; }
            set { _dbCreated = value; }
        }

        #endregion Not Public Properties

        #region Public Properties

        public bool CanKeepStatusInDb
        {
            get { return _canKeepStatusInDb; }
        }

        #endregion Public Properties

        #region Public Methods

        public void ReleaseStatusResources()
        {
            if (DbCreated)
            {
                DataProvider.RemoveSchema(EntityId);
                DbCreated = false;

                //TODO: check this is tested
            }
        }
        public List<TItemType> GetItems<TItemType>() where TItemType : BlobPart
        {
            return CurrentStorage.GetItems<TItemType>();
        }

        //TODO: document this could be done from the item directly attaching as another way to dot he same
        public void Store<TItemType>(TItemType item) where TItemType : BlobPart
        {
            if (item == null) throw new ArgumentNullException("item");
            item.Attach(this);
        }

        public void Remove<TItemType>(TItemType item) where TItemType : BlobPart
        {
            if (item == null) throw new ArgumentNullException("item");
            if(item.Domain==null || item.Domain.EntityId!=this.EntityId)
                throw new InvalidOperationException("The item to delete has not Domain or this is different then the current");
            item.Dettach();
        }


        #endregion Public Methods

        #region Not Public Methods

        private void KeepStatusInDataProvider()
        {
            if (EntityId == Guid.Empty)
                throw new InvalidOperationException("UniqueIdentifier must be set prior to this operation");


            if (!DbCreated)
            {
                DataProvider.CreateSchema(EntityId);
                DbCreated = true;
            }
        }

        #endregion Not Public Methods

       
    }
}